﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.ExceptionManagement;
using Kiiro.Logging;
using Kiiro.Model.EventHandlers;
using Kiiro.Model.TimerJobs;
using TimerJobConstants = Kiiro.Common.Utility.Constants.SPSiteDefinition.TimerJobs;
using WebFeatureIds = Kiiro.Common.Utility.Constants.SPSiteDefinition.WebFeatureIds;
using SiteFeatureIds = Kiiro.Common.Utility.Constants.SPSiteDefinition.SiteFeatureIds;

namespace Kiiro.Model.Utility
{
    public static class KiiroSolutionControllerHelpers
    {
        internal static void EnsureSiteEvents ( Guid siteCollectionId )
        {
            string assemblyName = typeof ( Kiiro.Model.EventHandlers.WebEventReceiver ).Assembly.FullName;
            string className = typeof ( Kiiro.Model.EventHandlers.WebEventReceiver ).FullName;

            using ( SPSite site = SPHelpers.GetSystemSite ( siteCollectionId ) )
            {
                using ( SPWeb web = site.RootWeb )
                {
                    try
                    {
                        web.AllowUnsafeUpdates = true;

                        web.EventReceivers.Cast<SPEventReceiverDefinition> ( )
                            .Where ( x => x.Class == className && ( x.Type == SPEventReceiverType.SiteDeleting || x.Type == SPEventReceiverType.SiteDeleted ) )
                            .ToList ( )
                            .ForEach ( delegate ( SPEventReceiverDefinition receiver ) { receiver.Delete ( ); } );

                        web.EventReceivers.Add ( SPEventReceiverType.SiteDeleting, assemblyName, className );
                        web.EventReceivers.Add ( SPEventReceiverType.SiteDeleted, assemblyName, className );
                    }
                    catch ( Exception ex )
                    {
                        ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                    }
                    finally
                    {
                        web.AllowUnsafeUpdates = false;
                    }
                }
            }
        }

        internal static void EnsureWebEvents ( Guid siteCollectionId, string serverRelativeUrl )
        {
            string assemblyName = typeof ( Kiiro.Model.EventHandlers.WebEventReceiver ).Assembly.FullName;
            string className = typeof ( Kiiro.Model.EventHandlers.WebEventReceiver ).FullName;

            using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
            {
                try
                {
                    web.AllowUnsafeUpdates = true;

                    web.EventReceivers.Cast<SPEventReceiverDefinition> ( )
                        .Where ( x => x.Class == className && ( x.Type == SPEventReceiverType.WebDeleting || x.Type == SPEventReceiverType.WebDeleted ))
                        .ToList ( )
                        .ForEach ( delegate ( SPEventReceiverDefinition receiver ) { receiver.Delete ( ); } );

                    web.EventReceivers.Add ( SPEventReceiverType.WebDeleting, assemblyName, className );
                    web.EventReceivers.Add ( SPEventReceiverType.WebDeleted, assemblyName, className );
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
                finally
                {
                    web.AllowUnsafeUpdates = false;
                }
            }
        }

        internal static void EnsureSiteFeatures ( Guid siteCollectionId, string serverRelativeUrl )
        {
            using ( SPSite elevatedSite = SPHelpers.GetSystemSite ( siteCollectionId ) )
            {
                if ( elevatedSite.AllWebs.AsSafeEnumerable().Count ( x => SPHelpers.IsKiiro(x)) > 0 )
                {
                    foreach ( string featureId in SiteFeatureIds.AllSiteFeatureIds )
                    {
                        try
                        {
                            elevatedSite.AllowUnsafeUpdates = true;

                            if ( elevatedSite.Features [ new Guid ( featureId ) ] != null )
                                elevatedSite.Features.Remove ( new Guid ( featureId ), true );
                            elevatedSite.Features.Add ( new Guid ( featureId ), true );
                        }
                        catch ( Exception ex )
                        {
                            ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                        }
                        finally
                        {
                            elevatedSite.AllowUnsafeUpdates = false;
                        }
                    }
                }
            }
        }

        internal static void EnsureWebFeaturesPortal ( Guid siteCollectionId, string serverRelativeUrl )
        {
            using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
            {
                try
                {
                    web.AllowUnsafeUpdates = true;

                    WebFeatureIds.AllPortalFeatureIds
                        .Except ( new List<string> { WebFeatureIds.Portal, WebFeatureIds.WPSandbox, WebFeatureIds.EventReceivers, WebFeatureIds.NavigationLists } )
                        .ToList ( )
                        .ForEach ( delegate ( string featureId )
                        {
                            if ( web.Features [ new Guid ( featureId ) ] != null )
                                web.Features.Remove ( new Guid ( featureId ), true );
                            web.Features.Add ( new Guid ( featureId ), true );
                        }
                    );

                    // ONLY ADD WPSANDBOX IF IT PREVIOUSLY EXISTED
                    if ( web.Features.Cast<SPFeature> ( )
                        .Count ( x => x.DefinitionId == new Guid ( WebFeatureIds.WPSandbox ) ) > 0 )
                    {
                        web.Features.Remove ( new Guid ( WebFeatureIds.WPSandbox ), true );
                        web.Features.Add ( new Guid ( WebFeatureIds.WPSandbox ), true );
                    }
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
                finally
                {
                    web.AllowUnsafeUpdates = false;
                }
            }
        }

        internal static void EnsureWebFeaturesProject ( Guid siteCollectionId, string serverRelativeUrl )
        {
            using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
            {
                try
                {
                    web.AllowUnsafeUpdates = true;

                    WebFeatureIds.AllProjectFeatureIds
                        .Except ( new List<string> { WebFeatureIds.Project, WebFeatureIds.WPSandbox, WebFeatureIds.EventReceivers } )
                        .ToList ( )
                        .ForEach ( delegate ( string featureId )
                        {
                            if ( web.Features [ new Guid ( featureId ) ] != null )
                                web.Features.Remove ( new Guid ( featureId ), true );
                            web.Features.Add ( new Guid ( featureId ), true );
                        }
                    );

                    // ONLY ADD WPSANDBOX IF IT PREVIOUSLY EXISTED
                    if ( web.Features.Cast<SPFeature> ( )
                        .Count ( x => x.DefinitionId == new Guid ( WebFeatureIds.WPSandbox ) ) > 0 )
                    {
                        web.Features.Remove ( new Guid ( WebFeatureIds.WPSandbox ), true );
                        web.Features.Add ( new Guid ( WebFeatureIds.WPSandbox ), true );
                    }
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
                finally
                {
                    web.AllowUnsafeUpdates = false;
                }
            }
        }

        internal static void EnsureNavigationLists ( Guid siteCollectionId, string serverRelativeUrl )
        {
            using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
            {
                try
                {
                    web.AllowUnsafeUpdates = true;

                    if ( web.Features [ new Guid ( WebFeatureIds.NavigationLists ) ] != null )
                        web.Features.Remove ( new Guid ( WebFeatureIds.NavigationLists ), true );
                    web.Features.Add ( new Guid ( WebFeatureIds.NavigationLists ), true );
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
                finally
                {
                    web.AllowUnsafeUpdates = false;
                }
            }
        }

        internal static void EnsureListEventHandlers ( Guid siteCollectionId, string serverRelativeUrl )
        {
            using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
            {
                try
                {
                    web.AllowUnsafeUpdates = true;

                    if ( web.Features [ new Guid ( WebFeatureIds.EventReceivers ) ] != null )
                        web.Features.Remove ( new Guid ( WebFeatureIds.EventReceivers ), true );
                    web.Features.Add ( new Guid ( WebFeatureIds.EventReceivers ), true );
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
                finally
                {
                    web.AllowUnsafeUpdates = false;
                }
            }
        }

        internal static void EnsureTimerJobs ( Guid siteCollectionId )
        {
            EnsureStatisticsJob ( siteCollectionId );
            EnsureDiscussionEmailJob ( siteCollectionId );
        }

        internal static void RemoveTimerJobs ( Guid siteCollectionId, string serverRelativeUrl )
        {
            RemoveStatisticsJob ( siteCollectionId );
            RemoveDiscussionEmailJob ( siteCollectionId );
        }

        internal static void EnsureProject ( Guid siteCollectionId, string serverRelativeUrl )
        {
            Project project = ProjectsModel.GetByServerRelativeWebUrl ( siteCollectionId, serverRelativeUrl );
            bool sandboxActivated = project != null && project.IsWPSandboxActivated;

            EnsureWPSandbox ( siteCollectionId, serverRelativeUrl, sandboxActivated );
        }

        internal static void EnsureSetup ( Guid siteCollectionId, string serverRelativeUrl )
        {
            Guid webId = SPHelpers.GetWebId ( siteCollectionId, serverRelativeUrl, true );
            Setup setup = SetupModel.GetMidoriSetup ( siteCollectionId, serverRelativeUrl );
            bool sandboxActivated = setup != null && setup.IsWPSandboxActivated;

            EnsureWPSandbox ( siteCollectionId, serverRelativeUrl, sandboxActivated );
        }

        private static void EnsureWPSandbox ( Guid siteCollectionId, string serverRelativeUrl, bool sandboxActivated )
        {
            using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
            {
                try
                {
                    web.AllowUnsafeUpdates = true;
                    if ( sandboxActivated )
                    {
                        if ( web.Features.Cast<SPFeature> ( ).Count ( x => x.DefinitionId.ToString ( ) == WebFeatureIds.WPSandbox ) == 0 )
                            web.Features.Add ( new Guid ( WebFeatureIds.WPSandbox ), true );
                    }
                    else
                    {
                        if ( web.Features.Cast<SPFeature> ( ).Count ( x => x.DefinitionId.ToString ( ) == WebFeatureIds.WPSandbox ) > 0 )
                            web.Features.Remove ( new Guid ( WebFeatureIds.WPSandbox ), true );
                    }
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
                finally
                {
                    web.AllowUnsafeUpdates = false;
                }
            }
        }

        private static void EnsureDiscussionEmailJob ( Guid siteCollectionId )
        {
            using ( SPSite elevatedSite = SPHelpers.GetSystemSite ( siteCollectionId ) )
            {
                try
                {
                    RemoveDiscussionEmailJob ( siteCollectionId );

                    if ( !elevatedSite.WebApplication.IsAdministrationWebApplication )
                    {
                        string jobName = TimerJobConstants.DiscussionsJobName + siteCollectionId.ToString ( );
                        DiscussionEmailTimerJob timerJob = new DiscussionEmailTimerJob ( jobName, elevatedSite.WebApplication );
                        SPMinuteSchedule schedule = new SPMinuteSchedule { BeginSecond = 0, EndSecond = 59, Interval = 5 };
                        timerJob.Schedule = schedule;
                        SPSecurity.RunWithElevatedPrivileges ( delegate ( ) { timerJob.Update ( ); } );
                    }
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
            }
        }

        private static void RemoveDiscussionEmailJob ( Guid siteCollectionId )
        {
            using ( SPSite elevatedSite = SPHelpers.GetSystemSite ( siteCollectionId ) )
            {
                try
                {
                    string jobName = TimerJobConstants.DiscussionsJobName + siteCollectionId.ToString ( );

                    elevatedSite.WebApplication.JobDefinitions.Cast<SPJobDefinition> ( )
                        .Where ( x => x.Name == jobName || x.TypeName == TimerJobConstants.OldEmailJobType )
                        .ToList ( )
                        .ForEach ( delegate ( SPJobDefinition timerJob ) { timerJob.Delete ( ); } );
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
            }
        }

        private static void EnsureStatisticsJob ( Guid siteCollectionId )
        {
            using ( SPSite elevatedSite = SPHelpers.GetSystemSite ( siteCollectionId ) )
            {
                try
                {
                    RemoveStatisticsJob ( siteCollectionId );

                    if ( !elevatedSite.WebApplication.IsAdministrationWebApplication )
                    {
                        string jobName = TimerJobConstants.StatisticsJobName + siteCollectionId.ToString ( );
                        StatisticsTimerJob timerJob = new StatisticsTimerJob ( jobName, elevatedSite.WebApplication );
                        SPDailySchedule schedule = new SPDailySchedule { BeginHour = 1, EndHour = 2 };
                        timerJob.Schedule = schedule;
                        SPSecurity.RunWithElevatedPrivileges ( delegate ( ) { timerJob.Update ( ); } );
                    }
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
            }
        }

        private static void RemoveStatisticsJob ( Guid siteCollectionId )
        {
            using ( SPSite elevatedSite = SPHelpers.GetSystemSite ( siteCollectionId ) )
            {
                try
                {
                    string jobName = TimerJobConstants.StatisticsJobName + siteCollectionId.ToString ( );

                    elevatedSite.WebApplication.JobDefinitions.Cast<SPJobDefinition> ( )
                        .Where ( x => x.Name == jobName || x.TypeName == TimerJobConstants.OldStatsJobType )
                        .ToList ( )
                        .ForEach ( delegate ( SPJobDefinition timerJob ) { timerJob.Delete ( ); } );
                }
                catch ( Exception ex )
                {
                    ExceptionManagement.ExceptionManager.HandleException ( ex, false );
                }
            }
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.Model/Utility/KiiroSolutionControllerHelpers.cs $
 * 
 * 19    1/12/10 9:43a Camerons
 * 
 * 18    1/11/10 11:51a Camerons
 * 
 * 17    22/11/09 9:41p Camerons
 * 
 * 16    10/11/09 2:12p Camerons
 * 
 * 15    30/10/09 6:21p Camerons
 * 
 * 14    30/10/09 12:54p Camerons
 * 
 * 13    27/10/09 1:54p Camerons
 * Fix to KiiroPortal and KiiroProject features for properly attaching
 * event handlers, wait until lists are created before activating
 * Kiiro.EventHandlers feature
 * 
 * 12    15/10/09 5:09p Camerons
 * 
 * 11    15/10/09 1:04p Camerons
 * 
 * 10    15/10/09 11:40a Camerons
 * 
 * 9     15/10/09 10:51a Camerons
 * 
 * 8     15/10/09 9:34a Camerons
 * 
 * 7     10/06/09 1:10p Adamw
 * fix for enabling WPSandox on Projects
 * 
 * 6     11/09/09 3:17p Camerons
 * 
 * 5     8/09/09 10:51a Camerons
 * Moved KiiroSolutionControllerHelpers to the Kiiro.Model.Utility
 * namespace
 * 
 * 4     4/09/09 3:18p Camerons
 * 
 * 1     4/09/09 10:06a Camerons
 * 
 * 2     1/09/09 3:09p Camerons
 * 
 * 1     31/08/09 11:56a Camerons
 * 
 ************************************************************************/
